package com.video.service;

import com.alibaba.fastjson.JSON;
import com.qf.entity.Page;
import com.qf.entity.RunLogEntity;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.metrics.cardinality.ParsedCardinality;
import org.elasticsearch.search.collapse.CollapseBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.net.URLDecoder;
import java.util.*;

@Service
public class RunLogServiceImpl implements IRunLogService {

    @Autowired
    private RestHighLevelClient restClient;

    @Value("${elasticsearch.index}")
    private String indexName;

    @Override
    public boolean createIndex() throws IOException {

        CreateIndexRequest indexRequest = new CreateIndexRequest(indexName);
        Map<String, Object> settings = new HashMap<>();
        settings.put("number_of_shards", 5);
        settings.put("number_of_replicas", 1);
        indexRequest.settings(settings);

        //创建映射类型
        XContentBuilder builder = JsonXContent.contentBuilder()
                .startObject()
                .startObject("properties")

                .startObject("requestId")
                .field("type", "keyword")
                .endObject()

                .startObject("url")
                .field("type", "keyword")
                .endObject()

                .startObject("className")
                .field("type", "text")
                .field("index", false)
                .endObject()

                .startObject("methodName")
                .field("type", "text")
                .field("index", false)
                .endObject()

                .startObject("params")
                .field("type", "text")
                .field("index", false)
                .endObject()

                .startObject("result")
                .field("type", "text")
                .field("index", false)
                .endObject()

                .startObject("throwInfo")
                .field("type", "text")
                .field("index", false)
                .endObject()

                .startObject("order")
                .field("type", "integer")
                .field("index", false)
                .endObject()

                .startObject("time")
                .field("type", "date")
                .field("format", "yyyy-MM-dd HH:mm:ss")
                .field("index", false)
                .endObject()

                .endObject()
                .endObject();

        //设置映射类型
        indexRequest.mapping(builder);

        CreateIndexResponse response = restClient.indices().create(indexRequest, RequestOptions.DEFAULT);
        return response.isAcknowledged();
    }

    @Override
    public boolean isExistIndex() throws IOException {
        GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);
        boolean exists = restClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
        return exists;
    }

    @Override
    public boolean insertDoc(RunLogEntity runLogEntity) throws IOException {

        System.out.println("索引的内容：" + runLogEntity.toJson());

        IndexRequest indexRequest = new IndexRequest(indexName);
        indexRequest.type("_doc");
        indexRequest.source(runLogEntity.toJson(), XContentType.JSON);
        IndexResponse response = restClient.index(indexRequest, RequestOptions.DEFAULT);
        System.out.println("结果：" + (response.getShardInfo().getSuccessful() == 1));
        return response.getShardInfo().getSuccessful() == 1;
    }

    @Override
    public List<RunLogEntity> search(String reqId) throws IOException {

        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.types("_doc");
        searchRequest.source()
                .query(QueryBuilders.termQuery("requestId", reqId))
                .sort("order", SortOrder.ASC);
        SearchResponse response = restClient.search(searchRequest, RequestOptions.DEFAULT);
        //搜索数据
        //搜索数据
        List<RunLogEntity> runLogEntities = searchData(response);
        return runLogEntities;
    }

    @Override
    public Page<List<RunLogEntity>> searchList(Page page) throws IOException {

        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.types("_doc");
        searchRequest.source()
                .query(QueryBuilders.matchAllQuery())
                .collapse(new CollapseBuilder("requestId"))
                .from((page.getPage() - 1) * page.getPageSize())
                .size(page.getPageSize())
                .sort("order", SortOrder.ASC)
                .sort("time", SortOrder.DESC)
                .aggregation(AggregationBuilders.cardinality("agg").field("requestId"));
        SearchResponse response = restClient.search(searchRequest, RequestOptions.DEFAULT);
        //搜索数据
        List<RunLogEntity> runLogEntities = searchData(response);

        //统计数量
        ParsedCardinality aggregation = (ParsedCardinality) response.getAggregations().asList().get(0);
        long value = aggregation.getValue();

        page.setDataSum((int) value);
        page.setPageCount((int) (value % page.getPageSize() == 0 ? value / page.getPageSize() : value / page.getPageSize() + 1));
        page.setDatas(runLogEntities);

        return page;
    }

    @Override
    public boolean deleteDocs(Date startTime, Date endTime) throws IOException {

        DeleteByQueryRequest request = new DeleteByQueryRequest(indexName);
        request.types("_doc");
        request.setQuery(
                QueryBuilders.rangeQuery("time").
                        from(startTime, true).
                        to(endTime, true));

        BulkByScrollResponse response = restClient.deleteByQuery(request, RequestOptions.DEFAULT);

        System.out.println("删除：" + response.getDeleted());

        return response.getDeleted() > 0;
    }

    /**
     * 搜索方法的封装
     * @return
     */
    private List<RunLogEntity> searchData(SearchResponse response) throws IOException {

        List<RunLogEntity> logEntitys = new ArrayList<>();

        for (SearchHit hit : response.getHits().getHits()) {
            System.out.println("搜索结果：" + hit.getSourceAsString());
            Map<String, Object> fields = hit.getSourceAsMap();

            RunLogEntity runLogEntity = new RunLogEntity()
                    .setClassName(URLDecoder.decode(fields.get("className").toString(), "utf-8"))
                    .setMethodName(fields.get("methodName").toString())
                    .setOrder((int) fields.get("order"))
                    .setParams(JSON.parseObject(URLDecoder.decode(fields.get("params").toString(), "utf-8"), HashMap.class))
                    .setRequestId(fields.get("requestId").toString())
                    .setResult(URLDecoder.decode(fields.get("result").toString(), "utf-8"))
                    .setTime(fields.get("time").toString())
                    .setThrowInfo(URLDecoder.decode(fields.get("throwInfo").toString(), "utf-8"))
                    .setUrl(fields.get("url").toString());
            logEntitys.add(runLogEntity);
        }
        return logEntitys;
    }
}
